<style>
div.ztree_content_wrap {
}
div.ztree_content_wrap:hover {
  position: relative;
  z-index: 9999;
}
div.ztree_content_wrap div.left {
  float: left;
}

div.zTreeDemoBackground {
  text-align: left;
}

.expendIcon {
  background-position: -74px -36px;
  line-height: 0;
  margin: 0;
  width: 16px;
  height: 16px;
  display: inline-block;
  vertical-align: middle;
  border: 0 none;
  cursor: pointer;
  outline: none;
  position: absolute;
  top: 4px;
  background-color: transparent;
  background-repeat: no-repeat;
  background-attachment: scroll;
  background-image: url('../images/ztree/zTreeStandard.png');
}

ul.ztree {
  background: #ffffff;
  width: 100%;
  height: auto;
  overflow-x: auto;
}

.ztree * {
  padding: 0;
  margin: 0;
  font-size: 15px;
  font-family: Verdana, Arial, Helvetica, AppleGothic, sans-serif;
}

.ztree {
  margin: 0;
  padding: 5px;
  color: #333;
}

.ztree li {
  position: relative;
  padding: 0;
  margin: 0;
  list-style: none;
  line-height: 24px;
  text-align: left;
  white-space: nowrap;
  outline: 0;
}
.ztree li .t-b {
  position: absolute;
  border-top: 1px dashed #999;
  height: 1px;
  top: 14px;
  left: -10px;
  width: 20px;
}
.ztree li ul {
  position: relative;
  margin: 0;
  padding: 0 0 0 18px;
}
.ztree li .l-b {
  position: absolute;
  border-left: 1px dashed #999;
  height: 100%;
  top: -11px;
  left: -12px;
  width: 1px;
}
.ztree li .l-b-d {
  height: 24px;
}
.ztree li ul.line {
  background: url('../images/ztree/line_conn.gif') 0 0 repeat-y;
}

.ztree li a {
  padding: 1px 3px 0 5px;
  margin: 0;
  cursor: pointer;
  /* height: 17px; */
  color: #333;
  background-color: transparent;
  text-decoration: none;
  vertical-align: top;
  display: inline-block;
}

.ztree li a:hover {
  text-decoration: underline;
  color: blue;
}

.ztree li a.curSelectedNode {
  border-radius: 3px;
  padding-top: 0px;
  background-color: #191d22;
  color: #fff;
  height: 26px;
  border: 1px #191d22 solid;
  opacity: 0.8;
}

.ztree li a.curSelectedNode_Edit {
  padding-top: 0px;
  background-color: #ffe6b0;
  color: black;
  height: 16px;
  border: 1px #ffb951 solid;
  opacity: 0.8;
}

.ztree li a.tmpTargetNode_inner {
  padding-top: 0px;
  background-color: #316ac5;
  color: white;
  height: 16px;
  border: 1px #316ac5 solid;
  opacity: 0.8;
  filter: alpha(opacity=80);
}

.ztree li a.tmpTargetNode_prev {
}

.ztree li a.tmpTargetNode_next {
}

.ztree li a input.rename {
  height: 14px;
  width: 80px;
  padding: 0;
  margin: 0;
  font-size: 12px;
  border: 1px #7ec4cc solid;
  *border: 0px;
}

.ztree li span {
  line-height: 16px;
  margin-right: 2px;
  top: 3px;
  display: inline-block;
}

.ztree li span.button {
  line-height: 0;
  margin: 0;
  width: 12px;
  height: 12px;
  display: inline-block;
  border: 0 none;
  cursor: pointer;
  outline: none;
}

.ztree li span.button.chk {
  width: 13px;
  height: 13px;
  margin: 0 3px 0 0;
  cursor: auto;
}

.ztree li span.button.chk.checkbox_false_full {
  background-position: 0 0;
}

.ztree li span.button.chk.checkbox_false_full_focus {
  background-position: 0 -14px;
}

.ztree li span.button.chk.checkbox_false_part {
  background-position: 0 -28px;
}

.ztree li span.button.chk.checkbox_false_part_focus {
  background-position: 0 -42px;
}

.ztree li span.button.chk.checkbox_false_disable {
  background-position: 0 -56px;
}

.ztree li span.button.chk.checkbox_true_full {
  background-position: -14px 0;
}

.ztree li span.button.chk.checkbox_true_full_focus {
  background-position: -14px -14px;
}

.ztree li span.button.chk.checkbox_true_part {
  background-position: -14px -28px;
}

.ztree li span.button.chk.checkbox_true_part_focus {
  background-position: -14px -42px;
}

.ztree li span.button.chk.checkbox_true_disable {
  background-position: -14px -56px;
}

.ztree li span.button.chk.radio_false_full {
  background-position: -28px 0;
}

.ztree li span.button.chk.radio_false_full_focus {
  background-position: -28px -14px;
}

.ztree li span.button.chk.radio_false_part {
  background-position: -28px -28px;
}

.ztree li span.button.chk.radio_false_part_focus {
  background-position: -28px -42px;
}

.ztree li span.button.chk.radio_false_disable {
  background-position: -28px -56px;
}

.ztree li span.button.chk.radio_true_full {
  background-position: -42px 0;
}

.ztree li span.button.chk.radio_true_full_focus {
  background-position: -42px -14px;
}

.ztree li span.button.chk.radio_true_part {
  background-position: -42px -28px;
}

.ztree li span.button.chk.radio_true_part_focus {
  background-position: -42px -42px;
}

.ztree li span.button.chk.radio_true_disable {
  background-position: -42px -56px;
}

.ztree li span.button.switch {
  width: 12px;
  height: 12px;
}

.ztree li span.button.root_open {
  position: relative;
  border: 1px solid #000;
  background: rgb(255, 255, 255);
  z-index: 2;
  border-radius: 100%;
}

.ztree li span.button.root_close {
  position: relative;
  border: 1px solid #000;
  background: rgb(0, 0, 0);
  color: #fff;
  top: 1px;
  z-index: 2;
  border-radius: 100%;
}

.ztree li span.button.root_open::before {
  content: '-';
  text-align: center;
  display: block;
  width: 10px;
  height: 10px;
  line-height: 10px;
}
.ztree li span.button.root_close::before {
  content: '+';
  text-align: center;
  display: block;
  width: 10px;
  height: 10px;
  line-height: 10px;
  font-size: 12px;
}

.ztree li span.button.roots_open {
  background-position: -92px 0;
}

.ztree li span.button.roots_close {
  background-position: -74px 0;
}

.ztree li span.button.center_open {
  position: relative;
  border: 1px solid #000;
  background: rgb(255, 255, 255);
  z-index: 2;
  border-radius: 100%;
}

.ztree li span.button.center_close {
  position: relative;
  border: 1px solid #000;
  background: rgb(0, 0, 0);
  color: #fff;
  top: 1px;
  z-index: 2;
  border-radius: 100%;
}

.ztree li span.button.center_open::before {
  content: '-';
  text-align: center;
  display: block;
  width: 10px;
  height: 10px;
  line-height: 10px;
}
.ztree li span.button.center_close::before {
  content: '+';
  text-align: center;
  display: block;
  width: 10px;
  height: 10px;
  line-height: 10px;
  font-size: 12px;
}

.ztree li span.button.bottom_open {
  position: relative;
  border: 1px solid #000;
  background: rgb(255, 255, 255);
  z-index: 2;
  border-radius: 100%;
}

.ztree li span.button.bottom_close {
  position: relative;
  border: 1px solid #000;
  background: rgb(0, 0, 0);
  color: #fff;
  top: 1px;
  z-index: 2;
  border-radius: 100%;
}

.ztree li span.button.bottom_open::before {
  content: '-';
  text-align: center;
  display: block;
  width: 10px;
  height: 10px;
  line-height: 10px;
}
.ztree li span.button.bottom_close::before {
  content: '+';
  text-align: center;
  display: block;
  width: 10px;
  height: 10px;
  line-height: 10px;
  font-size: 12px;
}

.ztree li span.button.noline_open {
  background-position: -92px -72px;
}

.ztree li span.button.noline_close {
  background-position: -74px -72px;
}

.ztree li span.button.root_docu {
  background: none;
}

.ztree li span.button.roots_docu {
  background-position: -56px 0;
}

.ztree li span.button.center_docu {
  width: 6px;
  height: 6px;
  position: relative;
  top: 0px;
  left: 4px;
  border-radius: 100%;
  background: #999;
  z-index: 2;
}

.ztree li span.button.bottom_docu {
  width: 6px;
  height: 6px;
  position: relative;
  top: 0px;
  left: 4px;
  border-radius: 100%;
  background: #999;
  z-index: 2;
}

.ztree li span.button.noline_docu {
  background: none;
}

.ztree li span.button.ico_open {
  margin-right: 2px;
  background-position: -110px -16px;
  vertical-align: top;
  *vertical-align: middle;
}

.ztree li span.button.ico_close {
  margin-right: 2px;
  background-position: -110px 0;
  vertical-align: top;
  *vertical-align: middle;
}

.ztree li span.button.ico_docu {
  margin-right: 2px;
  background-position: -110px -32px;
  vertical-align: top;
  *vertical-align: middle;
}

.ztree li span.button.edit {
  margin-right: 2px;
  background-position: -110px -48px;
  vertical-align: top;
  *vertical-align: middle;
}

.ztree li span.button.remove {
  margin-right: 2px;
  background-position: -110px -64px;
  vertical-align: top;
  *vertical-align: middle;
}
/*.ztree li span.button.ico_loading{margin-right:2px; background:url('../images/ztree/loading.gif') no-repeat scroll 0 0 transparent;
vertical-align:top; *vertical-align:middle}*/
ul.tmpTargetzTree {
  background-color: #ffe6b0;
  opacity: 0.8;
  filter: alpha(opacity=80);
}

span.tmpzTreeMove_arrow {
  width: 16px;
  height: 16px;
  display: inline-block;
  padding: 0;
  margin: 2px 0 0 1px;
  border: 0 none;
  position: absolute;
  background-color: white;
  background-repeat: no-repeat;
  background-attachment: scroll;
  background-position: -110px -80px;
  background-image: url('../images/ztree/zTreeStandard.png');
  *background-image: url('../images/ztree/zTreeStandard.gif');
}

ul.ztree.zTreeDragUL {
  margin: 0;
  padding: 0;
  position: absolute;
  width: auto;
  height: auto;
  overflow: hidden;
  background-color: #cfcfcf;
  border: 1px #00b83f dotted;
  opacity: 0.8;
  filter: alpha(opacity=80);
}

.zTreeMask {
  z-index: 10000;
  background-color: #cfcfcf;
  opacity: 0;
  filter: alpha(opacity=0);
  position: absolute;
}

.loadSyncNode {
  width: 16px;
  height: 16px;
  position: relative;
  display: inline-block;
  background-image: url('');
}
.clearfloat {
  clear: both;
}
</style>

<template>
  <!--（ztree－🌲）-->
  <div class="ztree_content_wrap"
       v-if='treeDataSource.length>0'>
    <div class="zTreeDemoBackground left">
      <ul class="ztree">
        <ztree-item v-for='(m,i) in treeDataSource'
                    :key='i'
                    :model.sync='m'
                    :num.sync='i'
                    root='0'
                    :nodes.sync='treeDataSource.length'
                    :callback='func'
                    :expandfunc='expand'
                    :cxtmenufunc='contextmenu'
                    :trees.sync='treeDataSource'></ztree-item>
      </ul>
    </div>
    <div class="clearfloat"></div>
  </div>
</template>

<script>
import Vue from 'vue'
export default {
  data () {
    return {
      treeDataSource: []
    }
  },
  name: 'ocTree',
  props: {
    // 树数据
    list: {
      type: Array,
      twoWay: true
    },
    // 点击节点回调
    func: {
      type: Function,
      default: null
    },
    // 点击展开回调
    expand: {
      type: Function,
      default: null
    },
    // 右击事件
    contextmenu: {
      type: Function,
      default: function () { }
    },
    // 是否展开
    isOpen: {
      type: Boolean,
      twoWay: true,
      default: false
    }
  },
  watch: {
    list: {
      handler: function () {
        this.initTreeData()
      },
      deep: true
    }
  },
  methods: {
    initTreeData () {
      let tempList = JSON.parse(JSON.stringify(this.list))
      // 递归操作，增加删除一些属性。比如: 展开/收起
      let recurrenceFunc = data => {
        data.forEach(m => {
          if (!m.hasOwnProperty('clickNode')) {
            m.clickNode = m.hasOwnProperty('clickNode') ? m.clickNode : false
          }
          m.Children = m.Children || []
          if (!m.hasOwnProperty('isFolder')) {
            m.isFolder = m.hasOwnProperty('open') ? m.open : this.isOpen
          }
          if (!m.hasOwnProperty('isExpand')) {
            m.isExpand = m.hasOwnProperty('open') ? m.open : this.isOpen
          }
          m.loadNode = 0
          recurrenceFunc(m.Children)
        })
      }
      recurrenceFunc(tempList)
      this.treeDataSource = tempList
    }
  },
  components: {
    // 组件
    ztreeItem: {
      name: 'ztreeItem',
      props: {
        model: {
          type: Object,
          twoWay: true
        },
        num: {
          type: Number,
          twoWay: true
        },
        nodes: {
          type: Number,
          twoWay: true,
          default: 0
        },
        trees: {
          type: Array,
          twoWay: true,
          default: []
        },
        root: {
          type: String,
          twoWay: true
        },
        callback: {
          type: Function
        },
        expandfunc: {
          type: Function
        },
        cxtmenufunc: {
          type: Function
        }
      },
      created () {
        if (this.root === 0) {
          this.Func(this.trees[0])
        }
      },
      methods: {
        Func (m) {
          //
          // 查找点击的子节点
          var recurFunc = (data, list) => {
            data.forEach(i => {
              if (i.User.id === m.User.id) {
                i.clickNode = true
                if (typeof this.callback === 'function') {
                  this.callback.call(null, m, list, this.trees)
                }
              } else {
                i.clickNode = false
              }
              if (i.Children) {
                recurFunc(i.Children, i)
              }
            })
          }
          recurFunc(this.trees, this.trees)
        },
        open (m) {
          m.isExpand = !m.isExpand
          if (typeof this.expandfunc === 'function' && m.isExpand) {
            if (m.loadNode !== 2) {
              this.expandfunc.call(null, m)
            } else {
              m.isFolder = !m.isFolder
            }
          } else {
            m.isFolder = !m.isFolder
          }
        }
      },
      computed: {
        // 给（根 和 子树）赋值不同的样式
        rootClass () {
          let strRootClass = ''
          // 根判断
          if (this.root === '0') {
            this.model.Children = this.model.Children || []
            strRootClass =
              this.num === 0 && this.model.Children.length === 0
                ? 'roots_docu'
                : this.nodes === 1 ||
                  (this.num === 0 && this.nodes !== this.num + 1)
                  ? 'root_'
                  : this.nodes === this.num + 1 ? 'bottom_' : 'center_'
            // 子树判断
          } else if (this.root === '1') {
            this.model.Children = this.model.Children || []
            strRootClass =
              this.nodes > 1 &&
                this.model.Children.length > 0 &&
                this.nodes !== this.num + 1
                ? 'center_'
                : (this.num === 0 && this.nodes > 1) ||
                  this.nodes !== this.num + 1
                  ? 'center_docu'
                  : (this.nodes === 1 && this.num !== 0) ||
                    (this.nodes === this.num + 1 &&
                      this.model.Children.length > 0)
                    ? 'bottom_'
                    : 'bottom_docu'
          }
          return strRootClass
        },
        // 是否有儿子节点
        isChildren () {
          return this.num + 1 !== this.nodes
        },
        // 展开/收起
        prefixClass () {
          let returnChar = ''
          if (this.rootClass.indexOf('docu') === -1) {
            if (this.model.isFolder) {
              returnChar = 'open'
            } else {
              returnChar = 'close'
            }
          }
          if (
            this.model.Children.length === 0 &&
            this.rootClass.indexOf('docu') === -1
          ) {
            returnChar = 'docu'
          }
          return returnChar
        },
        liClassVal () {
          return 'level' + this.num
        },
        spanClassVal () {
          return (
            'button level' +
            this.num +
            ' switch ' +
            this.rootClass +
            this.prefixClass
          )
        },
        aClassVal () {
          return this.model.clickNode
            ? 'level' + this.num + ' curSelectedNode'
            : 'level' + this.num
        },
        ulClassVal () {
          return this.ischildren && this.model.Children.length > 0
            ? 'level' + this.num + ' line'
            : 'level' + this.num
        },
        clb () {
          return this.rootClass === 'bottom_' ? 'l-b l-b-d' : 'l-b'
        },
        ctb () {
          return 't-b '
        }
      },
      template: `<li :class="liClassVal">
<div :class="clb" v-if="rootClass!='root_'"></div>
<span :class="spanClassVal" @click='open(model)'></span>
<a :class="aClassVal" @click='Func(model)' @contextmenu.prevent='cxtmenufunc(model)'>
<span :class="{loadSyncNode:model.loadNode==1}" v-if='model.loadNode==1'></span>
<span :class='model.iconClass' v-show='model.iconClass' v-else></span>
<span class="node_name">{{model.User.user_name}}<span style="color:rgb(45, 140, 240);">({{model.User.group_name}})</span></span>
</a>
<ul :class="ulClassVal" v-show='model.isFolder'>
<ztree-item v-for="(item,i) in model.Children" :key='i' :callback='callback' :expandfunc='expandfunc' :cxtmenufunc='cxtmenufunc' :model.sync="item" :num.sync='i' root='1' :nodes.sync='model.Children.length' :trees.sync='trees'></ztree-item>
</ul>
</li>`
    }
  },
  update () {
    this.initTreeData()
  },
  mounted () {
    Vue.nextTick(() => {
      this.initTreeData()
    })
  }
}
</script>
